home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 25 / AMIGAplus Sonderheft 25 (2000)(Falke)(DE)(Track 1 of 4)[!].iso / PublicDomain / Anwendungen / yacoder / decode.c < prev    next >
C/C++ Source or Header  |  1998-05-07  |  6KB  |  267 lines

  1. /*
  2.  * $Header: /usr/people/tcl/src/uutar/RCS/decode.c,v 1.1.1.3 1993/09/11 18:42:17 tcl Exp $
  3.  * Tom Lawrence
  4.  * tcl@sgi.com
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <fcntl.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <strings.h>
  12. #include <ctype.h>
  13. #include "codes.h"
  14.  
  15. /*
  16.  * given a string with n tokens separated by white space in it, and a
  17.  * pointer to a char vector, create a vector with each pointer pointing
  18.  * to a successive token and null terminate the tokens.  Return the
  19.  * number of tokens or -1 on error.  This routine is destructive to the
  20.  * passed string
  21.  */
  22. #define IS_WHITE_SPACE(c) (c == ' ' || c == '\t')
  23. #define VECLEN 10
  24.  
  25. FILE *infp, *outfp;
  26.  
  27. static int
  28. tokenize(string, vector)
  29.     char *string;
  30.     char **vector;
  31. {
  32.     int tokens;
  33.     enum {
  34.     WHITE_SPACE,
  35.     TOKEN
  36.     } state;
  37.     char *c;
  38.  
  39.     /* scan through the string setting up the vector pointers and
  40.      * null terminating the tokens
  41.      */
  42.     tokens = 0;
  43.     state = WHITE_SPACE;
  44.  
  45.     for(c = string; *c; c++) {
  46.     if (state == WHITE_SPACE && !IS_WHITE_SPACE(*c)) {
  47.         /* just hit beginning of a token */
  48.         vector[tokens] = c;
  49.         tokens++;
  50.         state = TOKEN;
  51.  
  52.         if (tokens >= VECLEN) {
  53.         fprintf(stderr, "too many tokens in input\n");
  54.         exit(1);
  55.         }
  56.     }
  57.     else if (state == TOKEN && IS_WHITE_SPACE(*c)) {
  58.         /* just ended a token */
  59.         *c = 0;
  60.         state = WHITE_SPACE;
  61.     }
  62.     }
  63.     return(tokens);
  64. }
  65.  
  66. /* normally I'd use strtol for this, but strtol can't handle
  67.  * unsigned values greater than 0x7FFFFFFF on some machines.
  68.  */
  69. static unsigned int
  70. hex2long(str)
  71.     char *str;
  72. {
  73.     unsigned long ret = 0;
  74.     char *c, c1;
  75.  
  76.     for(c = str; *c; c++) {
  77.     c1 = *c;
  78.     if (c1 >= '0' && c1 <= '9')
  79.         c1 -= '0';
  80.     else if (c1 >= 'a' && c1 <= 'f')
  81.         c1 -= ('a' - 10);
  82.     else if (c1 >= 'A' && c1 <= 'F')
  83.         c1 -= ('A' - 10);
  84.     ret = (ret << 4) + c1;
  85.     }
  86.     return(ret);
  87. }
  88.  
  89. static void
  90. usage()
  91. {
  92.     printf("options:\n");
  93.     printf("-i <inputfile>\n");
  94.     printf("-o <outputfile>\n");
  95.     exit(1);
  96. }
  97.  
  98. /* parse command line arguments */
  99. static void
  100. parse(argc, argv)
  101.     int argc;
  102.     char **argv;
  103. {
  104.     char *infile, *outfile;
  105.  
  106.     infile = outfile = 0;
  107.  
  108.     while(--argc) {
  109.     argv++;
  110.     if (!strcmp(*argv, "-i")) {
  111.         if (argc < 2)
  112.         usage();
  113.         argc--;
  114.         argv++;
  115.         infile = *argv;
  116.     }
  117.     else if (!strcmp(*argv, "-o")) {
  118.         if (argc < 2)
  119.         usage();
  120.         argc--;
  121.         argv++;
  122.         outfile = *argv;
  123.     }
  124.     else
  125.         usage();
  126.     }
  127.  
  128.     /* open input stream */
  129.     if (infile) {
  130.     if ((infp = fopen(infile, "r")) == 0) {
  131.         perror(infile);
  132.         exit(1);
  133.     }
  134.     }
  135.     else
  136.     infp = stdin;
  137.  
  138.     /* open output stream or leave it for later if no output file
  139.      * was specified 
  140.      */
  141.     if (outfile) {
  142.     if ((outfp = fopen(outfile, "w")) == 0) {
  143.         perror(outfile);
  144.         exit(1);
  145.     }
  146.     }
  147.     else
  148.     outfp = 0;
  149. }
  150.  
  151. main(argc, argv)
  152.     int argc;
  153.     char **argv;
  154. {
  155.     char buffer[1024], *tokens[VECLEN], *c, out;
  156.     int state, numtokens, outfd, buf_offset, lookforend;
  157.     unsigned int cksum;
  158.     unsigned short buf;
  159.  
  160.     /* parse command line arguments */
  161.     parse(argc, argv);
  162.  
  163.     state = 0;
  164.  
  165.     /* clear the output buffer */
  166.     buf = 0;
  167.     buf_offset = 16;
  168.  
  169.     cksum = 0;
  170.     lookforend = 0;
  171.  
  172.     /* scan the input file */
  173.     while(fgets(buffer, sizeof(buffer), infp)) {
  174.     /* remove any newlines */
  175.     if (c = index(buffer, '\n'))
  176.         *c = 0;
  177.  
  178.     /* if this line is blank, check for and END keyword
  179.      * on the next line
  180.      */
  181.     if (*buffer == 0) {
  182.         lookforend = 1;
  183.         continue;
  184.     }
  185.  
  186.     /* state 0 == haven't seen BEGIN yet */
  187.     if (state == 0) {
  188.         if (!strncmp(buffer, "BEGIN ", 6)) {
  189.         state = 1;
  190.         numtokens = tokenize(buffer, tokens);
  191.         if (numtokens < 4) {
  192.             fprintf(stderr, "incomplete BEGIN line in encoded file\n");
  193.             exit(1);
  194.         }
  195.  
  196.         /* if output file wasn't specified on command line, use the
  197.          * one encoded in the input file
  198.          */
  199.         if (outfp == 0) {
  200.             /* use open() so we can specify the mode */
  201.             if ((outfd = open(tokens[2], O_WRONLY | O_CREAT | O_TRUNC, 
  202.                       strtol(tokens[1], 0, 8))) < 0) {
  203.             perror(tokens[2]);
  204.             exit(1);
  205.             }
  206.             outfp = fdopen(outfd, "w");
  207.         }
  208.         /* parse the character set and initialize the
  209.          * codes accordingly
  210.          */
  211.         parse_charval_list(tokens[3]);
  212.         init_codes(DECODE);
  213.         }
  214.     }
  215.  
  216.     /* state != 0 and we're looking for the END token */
  217.     else if (lookforend && !strncmp(buffer, "END ", 4)) {
  218.         numtokens = tokenize(buffer, tokens);
  219.  
  220.         /* issue checksum error if there's a mismatch */
  221.         if (numtokens < 2 || hex2long(tokens[1]) != cksum) {
  222.         fprintf(stderr, "checksum error.\n");
  223.         fprintf(stderr, "saw %X, computed %X\n",
  224.             hex2long(tokens[1]), cksum);
  225.         exit(1);
  226.         }
  227.         exit(0);
  228.     }
  229.  
  230.     /* state != 0 so this is a data line. Decode it */
  231.     else {
  232.         for(c = buffer; *c; c++) {
  233.  
  234.         /* check for garbage characters in the input */
  235.         if (!codes[*c].inuse) {
  236.             fprintf(stderr, "invalid char ");
  237.             if (isprint(*c))
  238.             fprintf(stderr, "\'%c\' ", *c);
  239.             fprintf(stderr, "(%d) in input", *c);
  240.             exit(1);
  241.         }
  242.  
  243.         /* append the variable length bitfield that maps to
  244.          * this input character to the output bitstream
  245.          */
  246.         buf_offset -= codes[*c].len;
  247.         buf |= (((unsigned short)(codes[*c].code) << buf_offset));
  248.  
  249.         /* if we've got an entire byte available in the output
  250.          * buffer, append it to the output file
  251.          */
  252.         if (buf_offset < 9) {
  253.             out = (char)(buf >> 8);
  254.             putc(out, outfp);
  255.             cksum = ((cksum << 7) | (cksum >> 25)) ^
  256.             (unsigned char)out;
  257.  
  258.             /* advance the output buffer */
  259.             buf_offset += 8;
  260.             buf <<= 8;
  261.         }
  262.         }
  263.     }
  264.     lookforend = 0;
  265.     }
  266. }
  267.